#ifndef STX_ALGORITHM_DISTANCE_HPP
#define STX_ALGORITHM_DISTANCE_HPP

#include <iterator>

namespace stx {

template<class Iterator, class Difference>
inline void
distance_impl(
    Iterator first,
    Iterator last,
    Difference& offset,
    std::input_iterator_tag)
{
    for (; first != last; ++first) {
        ++offset;
    }
}

template<class ForwardIterator, class Difference>
inline void
distance_impl(
    ForwardIterator first,
    ForwardIterator last,
    Difference& offset,
    std::forward_iterator_tag)
{
    for (; first != last; ++first) {
        ++offset;
    }
}

template<class BidirectionalIterator, class Difference>
inline void distance_impl(
    BidirectionalIterator first,
    BidirectionalIterator last,
    Difference& offset,
    std::bidirectional_iterator_tag)
{
    for (; first != last; ++first) {
        ++offset;
    }
}

template<class RandomAccessIterator, class Difference>
inline void
distance_impl(
    RandomAccessIterator first,
    RandomAccessIterator last,
    Difference& offset,
    std::random_access_iterator_tag)
{
    offset += last - first;
}

template<class Iterator>
inline typename std::iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last)
{
    typename std::iterator_traits<Iterator>::difference_type offset = 0;
    distance_impl(first, last, offset, typename std::iterator_traits<Iterator>::iterator_category());
    return (offset);
}

} // namespace stx

#endif // STX_ALGORITHM_DISTANCE_HPP
